package com.gwt.theOne.theLocal.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.gwt.theOne.theLocal.client.FetchDataService;
import com.gwt.theOne.theLocal.shared.CurrentWeather;
import com.gwt.theOne.theLocal.shared.DiggInfo;
import com.gwt.theOne.theLocal.shared.GoogleNews;
import com.gwt.theOne.theLocal.shared.LoginInfo;

public class FetchDataServiceImpl extends RemoteServiceServlet implements FetchDataService {

	private static final long serialVersionUID = 1L;

	public DiggInfo[] getDiggInfo(String city, boolean isSortByDate, boolean isIncludeNeighbours) {

		DiggInfo[] result = null;
		ArrayList<DiggInfo> diggInfoList = new ArrayList<DiggInfo>();
		int j = -1, limit = 0;
		String urlStr, cityJsonStr, title, url, description;;
		String[] nearByPlaces = null;

		String queryCity = city ;
		if(isIncludeNeighbours)
			nearByPlaces = getNearbyPlaces(city);
		if(nearByPlaces!=null)
			limit = nearByPlaces.length-1;		
		do			
		{
			if(isSortByDate)
				urlStr = "http://services.digg.com/2.0/search.search?query="+queryCity;			
			else
				urlStr = "http://services.digg.com/2.0/search.search?sort=submit_date-desc&query="+queryCity;
			try
			{
				cityJsonStr = getJSONData(urlStr);
				JSONArray topStories = new JSONObject(cityJsonStr).getJSONArray("stories");
				for (int i = 0; i < topStories.length(); ++i) {

					title = topStories.getJSONObject(i).getString("title");		
					url = topStories.getJSONObject(i).getString("href");
					description = topStories.getJSONObject(i).getString("description");
					diggInfoList.add(new DiggInfo(title,url,description));
				}
			}
			catch(Exception e)
			{
				return new DiggInfo[0];
			}
			j++;
			if (nearByPlaces!=null)
				queryCity = nearByPlaces[j];
		}while(j<limit);
		int size = diggInfoList.size();
		result = new DiggInfo[size];
		for(int k = 0; k<size;k++)
			result[k] = diggInfoList.get(k);
		return result;		
	}

	@Override
	public Boolean loadLocationNames() {

		Location locNames[] = new Location[80];
		locNames[0] = new Location("amsterdam");
		locNames[1] = new Location("bangaluru");
		locNames[2] = new Location("boston");
		locNames[3] = new Location("bloomington");
		locNames[4] = new Location("chicago");
		locNames[5] = new Location("dallas");
		locNames[6] = new Location("new Delhi");
		locNames[7] = new Location("frankfurt");
		locNames[8] = new Location("geneva");
		locNames[9] = new Location("hong kong");
		locNames[10] = new Location("hyderabad");
		locNames[11] = new Location("indianapolis");
		locNames[12] = new Location("indore");
		locNames[13] = new Location("jaipur");
		locNames[14] = new Location("kolkata");
		locNames[15] = new Location("madras");
		locNames[16] = new Location("rome");
		locNames[17] = new Location("sunnyvale");
		locNames[18] = new Location("seattle");
		locNames[19] = new Location("tokyo");
		locNames[20] = new Location("lucknow");
		locNames[21] = new Location("london");
		locNames[22] = new Location("los Angeles");
		locNames[23] = new Location("minneapolis");
		locNames[24] = new Location("madrid");		
		locNames[25] = new Location("mumbai");
		locNames[26] = new Location("new york");
		locNames[27] = new Location("prague");
		locNames[28] = new Location("oslo");
		locNames[29] = new Location("paris");		
		locNames[30] = new Location("rio de janeiro");		
		locNames[31] = new Location("san jose");
		locNames[32] = new Location("san diego");
		locNames[33] = new Location("san francisco");
		locNames[34] = new Location("santa barbara");		
		locNames[35] = new Location("venice");
		locNames[36] = new Location("secunderabad");
		locNames[37] = new Location("pune");
		locNames[38] = new Location("gurgaon");
		locNames[39] = new Location("chandigarh");
		locNames[40] = new Location("noida");
		locNames[41] = new Location("st.paul");
		locNames[42] = new Location("duluth");
		locNames[43] = new Location("bloomington");
		locNames[44] = new Location("kanpur");
		locNames[45] = new Location("new jersey");
		locNames[46] = new Location("nagpur");
		locNames[47] = new Location("madras");
		locNames[48] = new Location("manchester");
		locNames[49] = new Location("moscow");
		locNames[50] = new Location("sanford");
		locNames[51] = new Location("lebanon");
		locNames[52] = new Location("luxembourg City");
		locNames[53] = new Location("duluth");
		locNames[54] = new Location("nainital");

		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			for(int i=0; i< locNames.length; i++)
				pm.makePersistent(locNames[i]);	
			return new Boolean(true);
		}
		catch(Exception e)
		{
			return new Boolean(false);
		}
		finally {
			pm.close();
		}	
	}

	@Override
	@SuppressWarnings("unchecked")
	public String[] getLocationNames() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try{
			Query query = pm.newQuery(Location.class);			
			List<Location> locationNameList = (List<Location>)query.execute();
			String[] locationNames = new String[locationNameList.size()];
			for(int i=0; i<locationNameList.size(); i++)
				locationNames[i] = locationNameList.get(i).getName();
			return locationNames;
		}finally{
			pm.close();
		}
	}

	@Override
	public LoginInfo validateUserLogin(String requestUri) {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		LoginInfo loginInfo = new LoginInfo();

		if (user != null) {
			loginInfo.setLoggedIn(true);
			loginInfo.setEmailAddress(user.getEmail());
			loginInfo.setNickname(user.getNickname());
			loginInfo.setLogoutUrl(userService.createLogoutURL(requestUri));
		} else {
			loginInfo.setLoggedIn(false);
			loginInfo.setLoginUrl(userService.createLoginURL(requestUri));
		}
		return loginInfo;	    
	}

	@Override
	public Boolean addUserComment(String locName, String nickname,
			String emailAddress, String commentHtml) {
		UserComment userComment = new UserComment(locName, nickname, emailAddress, commentHtml, new Date());
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			pm.makePersistent(userComment);	
			return new Boolean(true);
		}
		catch(Exception e)
		{
			return new Boolean(false);
		}
		finally {
			pm.close();
		}	
	}

	@Override
	public GoogleNews[] getNews(String cityname, boolean sortedByRelevance, boolean includeNearbyCities) {
		GoogleNews[] news = null;
		String jsonQuery = null;
		String apiKey = "ABQIAAAAUatAjivAJ41Atlxr3K-hbhRA34sG9RIE2BYx69mpAes3xLwx-xRH8he8WD29KjlHC4ms4INDQDivGg";
		String apiURL = "https://ajax.googleapis.com/ajax/services/search/news?v=1.0&key=" + apiKey;

		jsonQuery = apiURL.concat("&rsz=7&q="+cityname);
		if (!sortedByRelevance){ // sorted by date
			jsonQuery = jsonQuery.concat("");
		}	
		GoogleNews[] localnews = getNewsFromGoogle(jsonQuery);

		if (!includeNearbyCities){

			return localnews;

		} else {  			

			String[] nearbyCities = getNearbyPlaces(cityname);
			if (nearbyCities == null){
				return localnews;
			}
			jsonQuery = apiURL.concat("&rsz=2&q="+nearbyCities[0]);
			if (!sortedByRelevance){ // sorted by date
				jsonQuery = jsonQuery.concat("");
			}	
			GoogleNews[] nearbyNews1 = getNewsFromGoogle(jsonQuery);

			jsonQuery = apiURL.concat("&rsz=2&q="+nearbyCities[1]);
			if (!sortedByRelevance){ // sorted by date
				jsonQuery = jsonQuery.concat("");
			}	
			GoogleNews[] nearbyNews2 = getNewsFromGoogle(jsonQuery);

			jsonQuery = apiURL.concat("&rsz=2&q="+nearbyCities[2]);
			if (!sortedByRelevance){ // sorted by date
				jsonQuery = jsonQuery.concat("");
			}	
			GoogleNews[] nearbyNews3 = getNewsFromGoogle(jsonQuery);
			news = new GoogleNews[localnews.length + nearbyNews1.length + nearbyNews2.length + nearbyNews3.length];

			int currentRow = 0;
			for (GoogleNews story: localnews){
				news[currentRow] = story;
				currentRow++;
			}
			for (GoogleNews story: nearbyNews1){
				news[currentRow] = story;
				currentRow++;
			}
			for (GoogleNews story: nearbyNews2){
				news[currentRow] = story;
				currentRow++;
			}
			for (GoogleNews story: nearbyNews3){
				news[currentRow] = story;
				currentRow++;
			}
		}
		return news;

	}

	private GoogleNews[] getNewsFromGoogle(String jsonQuery){

		GoogleNews[] news = null;

		try {
			String jsonResults = getJSONData(jsonQuery);
			JSONArray resultArray = new JSONObject(jsonResults).getJSONObject("responseData").getJSONArray("results");
			news = new GoogleNews[resultArray.length()];
			String title, content, url, imageurl = null;

			for (int i = 0; i < resultArray.length(); i++){

				title = resultArray.getJSONObject(i).getString("title");
				content = resultArray.getJSONObject(i).getString("content");
				url = resultArray.getJSONObject(i).getString("unescapedUrl");

				if (resultArray.getJSONObject(i).has("image")){

					JSONObject img = new JSONObject(resultArray.getJSONObject(i).getString("image"));
					imageurl = img.getString("tbUrl");
				}
				news[i] = new GoogleNews(title, content, url, imageurl);
			}

		}catch(JSONException e){
			e.printStackTrace();
		}

		return news;

	}

	private String[] getNearbyPlaces(String cityname) {

		String[] nearbyPlaces = getNearbyPlacesFromDatastore(cityname);
		if (nearbyPlaces == null){
			nearbyPlaces = getNearbyPlacesFromAPI(cityname);
		}
		return nearbyPlaces;
	}

	@SuppressWarnings("unchecked")
	private String[] getNearbyPlacesFromDatastore(String cityname){

		String[] nearbyPlaces = null;

		PersistenceManager pm = PMF.get().getPersistenceManager();

		try{
			Query query = pm.newQuery(NearbyPlaces.class);
			query.setFilter("cityname == cityParam");
			query.declareParameters("String cityParam");
			List<NearbyPlaces> nearbyPlacesList = (List<NearbyPlaces>)query.execute(cityname.toLowerCase());
			if (nearbyPlacesList!= null && nearbyPlacesList.size()>0){
				nearbyPlaces = new String[3];
				nearbyPlaces[0] = nearbyPlacesList.get(0).getNearbyPlace1();
				nearbyPlaces[1] = nearbyPlacesList.get(0).getNearbyPlace2();
				nearbyPlaces[2] = nearbyPlacesList.get(0).getNearbyPlace3();
			} 
		}finally{
			pm.close();
		}
		return nearbyPlaces;

	}

	private String[] getNearbyPlacesFromAPI(String cityname){
		try {
			String username = "anneceh";

			// First get latitude and longitude of city
			String apiURL = "http://api.geonames.org/searchJSON?q="+cityname+"&maxRows=10&username=" + username;			
			String resultString = getJSONData(apiURL);
			if(resultString.length()>0)
			{
				JSONArray cityJSON = new JSONObject(resultString).getJSONArray("geonames");
				long latitude, longitude;
				latitude = cityJSON.getJSONObject(0).getLong("lat");
				longitude = cityJSON.getJSONObject(0).getLong("lng");

				// Then get places within a 100 kilometer from that latitude and longitude
				apiURL = "http://api.geonames.org/findNearbyJSON?lat=" + 
				latitude + "&lng=" + longitude + "&radius=300&username="+username; 
				resultString = getJSONData(apiURL);
				JSONArray nearbyCitiesJSON = new JSONObject(resultString).getJSONArray("geonames");
				String[] cityNames = new String[nearbyCitiesJSON.length()];
				for (int i = 0; i < nearbyCitiesJSON.length(); i++){
					cityNames[i] = nearbyCitiesJSON.getJSONObject(i).getString("name");
				}

				return cityNames;
			}
			else
			{
				return new String[]{"","",""};
			}
		}catch(JSONException e){
			e.printStackTrace();
		}
		return null;
	}

	private String getJSONData(String apiUrl) {
		StringBuilder json = new StringBuilder();
		try{
			URL url = new URL(apiUrl.replaceAll(" ", "%20"));
			URLConnection connection = url.openConnection();
			connection.addRequestProperty("referer", "http://localgwt.appspot.com");
			BufferedReader in = new BufferedReader(
					new InputStreamReader(
							connection.getInputStream()));
			String inputLine;
			while ((inputLine = in.readLine()) != null){ 
				json.append(inputLine.trim());
			}
			in.close();
		}catch(MalformedURLException e){
			e.printStackTrace();
		}catch(IOException e){
			e.printStackTrace();
		}
		return json.toString();
	}

	public Boolean insertNearbyPlacesIntoDatabase() {
		NearbyPlaces[] nearbyPlaces = new NearbyPlaces[45];

		nearbyPlaces[0] = new NearbyPlaces("amsterdam", "", "", "netherlands");
		nearbyPlaces[1] = new NearbyPlaces("bangaluru", "Chennai", "Mysore", "cochin");
		nearbyPlaces[2] = new NearbyPlaces("boston", "", "", "");
		nearbyPlaces[3] = new NearbyPlaces("bloomington", "indianapolis", "", "");
		nearbyPlaces[4] = new NearbyPlaces("chicago", "chaimpaign", "", "illinois");
		nearbyPlaces[5] = new NearbyPlaces("dallas", "austin", "", "texas");
		nearbyPlaces[6] = new NearbyPlaces("New delhi", "Chandigarh", "Noida", "Gurgaon");
		nearbyPlaces[7] = new NearbyPlaces("frankfurt", "", "", "germany");
		nearbyPlaces[8] = new NearbyPlaces("geneva", "", "", "switzerland");
		nearbyPlaces[9] = new NearbyPlaces("hong kong", "", "", "");
		nearbyPlaces[10] = new NearbyPlaces("hyderabad", "", "secunderabad", "india");
		nearbyPlaces[11] = new NearbyPlaces("indianapolis", "bloomington", "", "");
		nearbyPlaces[12] = new NearbyPlaces("indore", "", "", "india");
		nearbyPlaces[13] = new NearbyPlaces("jaipur", "ajmer", "alwar", "india");
		nearbyPlaces[14] = new NearbyPlaces("kolkata", "puri", "", "india");
		nearbyPlaces[15] = new NearbyPlaces("madras", "", "", "india");
		nearbyPlaces[16] = new NearbyPlaces("rome", "vatican", "napoli", "italy");
		nearbyPlaces[17] = new NearbyPlaces("sunnyvale", "san jose", "san diego", "san francisco");
		nearbyPlaces[18] = new NearbyPlaces("seattle", "", "", "washington");
		nearbyPlaces[19] = new NearbyPlaces("tokyo", "", "", "japan");
		nearbyPlaces[20] = new NearbyPlaces("lucknow", "Kanpur", "", "");
		nearbyPlaces[21] = new NearbyPlaces("london", "burmingham", "", "britain");
		nearbyPlaces[22] = new NearbyPlaces("los angeles","santa monica", "anaheim", "california");
		nearbyPlaces[23] = new NearbyPlaces("minneapolis", "st.paul", "duluth", "minnesota");
		nearbyPlaces[24] = new NearbyPlaces("madrid", "", "", "spain");		
		nearbyPlaces[25] = new NearbyPlaces("mumbai", "pune", "nasik", "india");
		nearbyPlaces[26] = new NearbyPlaces("new york", "manhattan", "brooklyn", "queens");
		nearbyPlaces[27] = new NearbyPlaces("prague", "vltava", "bohemia", "czech");
		nearbyPlaces[28] = new NearbyPlaces("oslo", "bergen", "trondheim", "norway");
		nearbyPlaces[29] = new NearbyPlaces("paris", "seine", "montmartre","france");		
		nearbyPlaces[30] = new NearbyPlaces("rio de janeiro","","", "brazil");		
		nearbyPlaces[31] = new NearbyPlaces("san jose", "san francisco", "sacramento", "sunnyvale");
		nearbyPlaces[32] = new NearbyPlaces("san diego", "los angeles", "tijuana", "california");
		nearbyPlaces[33] = new NearbyPlaces("san francisco", "san jose", "sacramento", "sunnyvale");
		nearbyPlaces[34] = new NearbyPlaces("santa barbara", "santa clara", "los angeles", "sunnyvale");		
		nearbyPlaces[35] = new NearbyPlaces("venice", "veneto", "padua", "italy");
		nearbyPlaces[36] = new NearbyPlaces("washington", "district of columbia", "capitol heights", "annandale");
		nearbyPlaces[37] = new NearbyPlaces("chennai", "bengaluru", "mysore", "cochin");
		nearbyPlaces[38] = new NearbyPlaces("gurgaon", "chandigarh", "noida", "new delhi");
		nearbyPlaces[39] = new NearbyPlaces("pune", "nasik", "mumbai", "india");
		nearbyPlaces[40] = new NearbyPlaces("kanpur", "lucknow", "", "");
		nearbyPlaces[41] = new NearbyPlaces("duluth", "minneapolis", "st. paul", "");
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {

			for(int i=0; i< nearbyPlaces.length; i++){
				pm.makePersistent(nearbyPlaces[i]);
			}

		} finally {
			pm.close();
		}

		return new Boolean(true);
	}

	@Override
	@SuppressWarnings("unchecked")
	public String[][] getUserComments(String location, boolean isIncNeighborChked) {
		String[][] userComments = new String [0][0];
		PersistenceManager pm = PMF.get().getPersistenceManager();
		String[] nearByPlaces = null;
		if(isIncNeighborChked)
			nearByPlaces = getNearbyPlaces(location);
		String recordCity;
		try{
			Query query = pm.newQuery(UserComment.class);			
			List<UserComment> userCommentsList = (List<UserComment>)query.execute();
			ArrayList<UserComment> tempList = new ArrayList<UserComment>();
			for(UserComment uc : userCommentsList)
			{
				recordCity = uc.getLocName();
				if(recordCity.equals(location))
				{
					tempList.add(uc);
				}
				else if(isIncNeighborChked &&(recordCity.equals(nearByPlaces[0]) || recordCity.equals(nearByPlaces[1]) || recordCity.equals(nearByPlaces[2])))
				{
					tempList.add(uc);
				}
			}			
			int matchUCs = tempList.size();
			userComments = new String[matchUCs][2];
			for(int k=0;k<matchUCs;k++)
			{
				userComments[k][0] = tempList.get(k).getUserName();
				userComments[k][1] = tempList.get(k).getCommentHtmlStr();
			}
			return userComments;
		}finally{
			pm.close();
		}
	}

	public CurrentWeather getWeatherNews(String cityName){
		try
		{
			String api_key = "236e848e96181643112602";
			String URL_1 = "http://www.worldweatheronline.com/feed/weather.ashx?q=";
			String URL_2 = "&format=json&num_of_days=1&key="+api_key;
			String updatedCityName = cityName.replaceAll(" ", "%20"); 
			String weatherURL = URL_1 + updatedCityName + URL_2;
			String json = getJSONData(weatherURL);
			CurrentWeather currWeather = null;
			if(json!=null)
			{
				JSONArray weatherDetails = new JSONObject(json).getJSONObject("data").getJSONArray("current_condition");
				JSONArray moreDetails = new JSONObject(json).getJSONObject("data").getJSONArray("weather");
				JSONObject weather_News = weatherDetails.getJSONObject(0);
				JSONObject details = moreDetails.getJSONObject(0);
				JSONArray weatherImage = weather_News.getJSONArray("weatherIconUrl");
				JSONObject weatherImageUrl = weatherImage.getJSONObject(0);
				JSONArray weatherDesc = weather_News.getJSONArray("weatherDesc");
				JSONObject weather_Desc = weatherDesc.getJSONObject(0);
				String weatherDescription = weather_Desc.getString("value");

				String weatherIconUrl = weatherImageUrl.getString("value");

				System.out.println(weatherIconUrl);
				String location = cityName;
				String date = details.getString("date");
				String high = details.getString("tempMaxF");
				String low = details.getString("tempMinF");;
				String temperature = weather_News.getString("temp_F");
				String visibility = weather_News.getString("visibility");
				String humidity=weather_News.getString("humidity");
				String cloudCover = weather_News.getString("cloudcover");
				String pressure = weather_News.getString("pressure");
				String windDir = weather_News.getString("winddir16Point");
				String windSpeed = weather_News.getString("windspeedMiles");
				currWeather = new CurrentWeather(location, date, high, low, temperature, visibility, humidity, cloudCover, weatherIconUrl, windDir, windSpeed, weatherDescription, pressure);
			}
			return currWeather;
		}
		catch(JSONException e)
		{
			e.printStackTrace();
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
}